#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <dlfcn.h>

#include <imp/imp_audio.h>
#include <imp/imp_log.h>
#include <imp/imp_system.h>
#include <system/system.h>

#include "audio_process.h"
#ifdef DMALLOC
#include <imp/dmalloc.h>
#endif
#define TAG "AudioProcess"

void *g_lib_audioProcess_handle = NULL;

static int file_is_exist(const char *strFilePath)
{
	if(NULL == strFilePath || 0 == strcmp(strFilePath,"")) {
		IMP_LOG_ERR(TAG,"fun:%s,strFilePath is empty\n",__func__);
		return -1;
	}
	if(access(strFilePath,F_OK) != 0)
		return -1;

	return 0;
}

static void *open_shared_library(const char *libFilePath)
{
	if(NULL == libFilePath){
		IMP_LOG_ERR(TAG,"fun:%s, lib file path  is empty\n",__func__);
		return NULL;
	}

	void *handle = NULL;
	handle = dlopen(libFilePath,RTLD_LAZY);
	if(NULL == handle) {
		IMP_LOG_ERR(TAG,"fun:%s dlopen failed.\n",__func__);
		return NULL;
	}

	return handle;
}

static void* user_defined_lib_path(const char *env,const char *libFileName)
{
	if (NULL == env||NULL == libFileName) {
		IMP_LOG_ERR(TAG,"env is NULL \n");
		return NULL;
	}

	void *handle = NULL;

	char *p = (char*)env;
	char *q = NULL;

	int bufSize = strlen(env) + strlen(libFileName) + 2;
	int nPos = 0;

	char *tmpBuf = NULL;
	tmpBuf = malloc(bufSize);
	if (NULL == tmpBuf) {
		IMP_LOG_ERR(TAG,"fun:%s,malloc space failed\n",__func__);
		return NULL;
	}

	memset(tmpBuf,0x0,bufSize);

	while(*p) {
		q = strchr(p,':');

		if(NULL == q) {
			memcpy(tmpBuf,p,strlen(p));
		} else {
			nPos = q-p;
			memcpy(tmpBuf,p,nPos);
		}

		strcat(tmpBuf,"/");
		strcat(tmpBuf,libFileName);

		if(0 == file_is_exist(tmpBuf)) {
			handle = open_shared_library(tmpBuf);
			break;
		}

		if(NULL == q)
			break;
		p = q+1;
		memset(tmpBuf,0x0,bufSize);
	}

	free(tmpBuf);
	tmpBuf = NULL;

	return handle;

}

static void* default_lib_path(const char *defaultDir, const char *libFileName)
{
	if(NULL == defaultDir||NULL == libFileName) {
		IMP_LOG_ERR(TAG,"fun:%s,defaultDir or libFileName is empty\n",__func__);
		return NULL;
	}
	void *handle = NULL;
	const char *p = defaultDir;
	const char *q = libFileName;

	int bufSize = strlen(p) + strlen(q) + 2;
	char *tmpBuf = NULL;
	tmpBuf = malloc(bufSize);
	if(NULL == tmpBuf) {
		IMP_LOG_ERR(TAG,"fun:%s,malloc tmpBuf failed\n",__func__);
		return NULL;
	}
	memset(tmpBuf,0x0,bufSize);
	strcat(tmpBuf,p);
	strcat(tmpBuf,"/");
	strcat(tmpBuf,q);

	if(file_is_exist(tmpBuf) != 0){
		IMP_LOG_INFO(TAG,"file:%s is not exist\n",tmpBuf);
		return NULL;
	}

	handle = open_shared_library(tmpBuf);

	free(tmpBuf);
	tmpBuf = NULL;

	return handle;
}

void* load_audioProcess_library(const char* defaultDir[],int num,const char *libFileName,const char *env)
{
	if(NULL == defaultDir || NULL == libFileName|| num <= 0 ) {
		return NULL;
	}

	void *handle = NULL;
	int i = 0;

	if (NULL != env) {  /*user defined way*/
		handle = user_defined_lib_path(env,libFileName);
		if (NULL != handle)
			return handle;
	}

	for(i = 0;i < num;i++) {  /*default way*/
		handle = default_lib_path(defaultDir[i],libFileName);
		if (NULL != handle)
			break;
	}

	return handle;
}

int get_fun_address(void *handle,FUN_TYPE funArr[],int num)
{
	 if(NULL == handle||NULL == funArr||num<=0) {
		IMP_LOG_ERR(TAG,"fun:%s,handle or funArr or num is not right value\n",__func__);
		return -1;
	}
	int i = 0;
	for(i = 0;i < num;i++) {
		*(funArr[i].pFun) = dlsym(handle,funArr[i].strFunName);
		if(dlerror() != NULL) {
			IMP_LOG_ERR(TAG,"line:%d,funName:%s dlsym failed\n",__LINE__,funArr[i].strFunName);
			return -1;
		}
	}

	return 0;
}

int free_audioProcess_library(void *handle)
{
	if(NULL == handle)
		return 0;

	if(dlclose(handle)!= 0)
		return -1;

	return 0;
}
